package com.lincoln.cartoon.updater.actuator;

import com.lincoln.cartoon.updater.annotation.Updater;
import com.lincoln.cartoon.updater.enums.UpdateTypeEnum;
import com.lincoln.cartoon.updater.interfaces.BaseUpdater;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

@Updater(updateType = UpdateTypeEnum.CARTOON, name = "鬼灭之刃")
@Slf4j
@Service
public class GMZRUpdater implements BaseUpdater {
    private Map<String, Object> param;
    private boolean isUpdate = false;
    private int percent = 0;

    private GMZRThread gmzrThread = null;

    private class GMZRThread extends Thread {
        @Override
        public void run() {
            loadCatalog();
        }
    }

    @Override
    public Map<String, Object> invoke(Map<String, Object> param) throws Exception {
        this.param = param;
        this.isUpdate = true;
        this.percent = 0;
        gmzrThread = new GMZRThread();
        gmzrThread.start();
        return new HashMap<>();
    }

    @Override
    public boolean isUpdate() {
        return this.isUpdate;
    }

    @Override
    public int percent() {
        return this.percent;
    }

    public String getPath() {
        if (System.getProperty("os.name").toLowerCase().contains("windows")) {
            return "D:/mh/鬼灭之刃/";
        } else if (System.getProperty("os.name").toLowerCase().contains("linux")) {
            return "/mh/鬼灭之刃";
        }
        return "";
    }

    public void loadCatalog() {
        String url = "http://comic.ikkdm.com";
        try {
            Date start = new Date();
            Document document = Jsoup.connect(url + "/comiclist/2126/index.htm").get();
            Elements elements = document.select("dd a");
            elements = elements.stream().filter(element -> element.html().length() > 1).collect(Collectors.toCollection(Elements::new));
            List<Catalog> res = elements.stream().map(element -> new Catalog(element.html(), element.html(), url + element.attr("href").replace("1.htm", ""))).collect(Collectors.toCollection(ArrayList::new));
            res.stream().filter(r -> !new File(getPath() + r.getAlias() + "/").exists()).forEach(r -> loadPages(r, 1, true));
            int pageCount = 0;
            for (Catalog catalog : res) {
                pageCount = pageCount + catalog.getPages().size();
            }
            log.info("共获取" + res.size() + "话");
            log.info("共获取" + pageCount + "页,用时:" + (new Date().getTime() - start.getTime()) + "ms");
            start = new Date();
            downloadPic(res);
            log.info("抓取完成,用时:" + (new Date().getTime() - start.getTime()) + "ms");
            this.percent = 100;
            this.isUpdate = false;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 查询所有页
     *
     * @param catalog
     * @param pageNo  第x页
     * @param cycle   是否递归
     */
    public void loadPages(Catalog catalog, int pageNo, boolean cycle) {
        try {
            log.info("加载[" + catalog.getAlias() + "]" + pageNo + "页");
            Document document = Jsoup.connect(catalog.getUrl() + pageNo + ".htm").get();
            String script = document.select("table").get(1).child(0).child(0).child(0).selectFirst("script").html();
            script = script.substring(script.indexOf("newkuku"), script.indexOf("'></a>", script.indexOf("newkuku")));
            Page page = new Page("http://v2.kukudm.com/" + script.substring(0, script.lastIndexOf("/", script.lastIndexOf("/") - 1)) + URLEncoder.encode(script.substring(script.lastIndexOf("/", script.lastIndexOf("/") - 1), script.lastIndexOf("/"))) + script.substring(script.lastIndexOf("/")));
            catalog.getPages().add(page);
            Element p = document.select("table").get(1).child(0).child(0).child(0);
            int pageCount = Integer.parseInt(p.html().substring(p.html().indexOf("共") + 1, p.html().indexOf("页")));
            int currentPage = Integer.parseInt(p.html().substring(p.html().indexOf("当前第") + 3, p.html().indexOf("页", p.html().indexOf("当前第") + 3)));
            if (pageCount > currentPage && cycle) {
                loadPages(catalog, pageNo + 1, true);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void downloadPic(List<Catalog> catalogs) {
        catalogs.forEach(catalog -> {
            for (int i = 0; i < catalog.getPages().size(); i++) {
                Page page = catalog.getPages().get(i);
                if (new File(getPath() + catalog.getAlias() + "/" + i + ".jpg").exists()) {
                    log.info("跳过下载图片:" + getPath() + catalog.getAlias() + "/" + i + ".jpg");
                    continue;
                }
                try {
                    URL url = new URL(page.getImgUrl());
                    URLConnection con = url.openConnection();
                    con.setConnectTimeout(5 * 1000);
                    InputStream is = con.getInputStream();
                    // 1K的数据缓冲
                    byte[] bs = new byte[1024];
                    // 读取到的数据长度
                    int len;
                    // 输出的文件流
                    String savePath = getPath() + catalog.getAlias() + "/";
                    File sf = new File(savePath);
                    if (!sf.exists()) {
                        sf.mkdirs();
                    }
                    OutputStream os = new FileOutputStream(sf.getPath() + "/" + i + ".jpg");
                    // 开始读取
                    while ((len = is.read(bs)) != -1) {
                        os.write(bs, 0, len);
                    }
                    // 完毕，关闭所有链接
                    os.close();
                    is.close();
                    log.info("下载图片:" + sf.getPath() + "/" + i + ".jpg");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

@Data
@NoArgsConstructor
class Catalog implements Serializable {
    /**
     * 章节名
     */
    private String name;

    /**
     * 别名
     */
    private String alias;

    /**
     * 抓取的url
     */
    private String url;

    /**
     * 页
     */
    private List<Page> pages = new ArrayList<>();

    public Catalog(String name, String alias, String url) {
        this.name = name;
        this.alias = alias;
        this.url = url;
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class Page implements Serializable {
    private String imgUrl;
}
